package com.ciwong.libs.utils.volley;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;

import com.ciwong.libs.utils.CWLog;

/**
 * Created by RES-KUNZHU on 2015/5/22.
 */
public class AsyncUploadLargeFileManager
{
    private static final int MAX_TASK_COUNT = 5;

    private static AsyncUploadLargeFileManager instance;

    private List<UploadFileListener> listenerList = new ArrayList<UploadFileListener>();

    private List<Task> executingList = new ArrayList<Task>();

    private PriorityQueue<Task> taskList;

    private AsyncUploadLargeFileManager()
    {
        taskList = new PriorityQueue<Task>(10, new TaskComparator());
    }

    public static AsyncUploadLargeFileManager getInstance()
    {
        if (instance == null)
        {
            instance = new AsyncUploadLargeFileManager();
        }
        return instance;
    }

    public void addTask(AsyncUploadLargeFile task, int priori)
    {
        Task tempTask = new Task(task, priori);
        if (executingList.contains(tempTask) || taskList.contains(tempTask))
        {
            return;
        }
        taskList.add(tempTask);
        executeTask();
    }

    public void registerListener(UploadFileListener listener)
    {
        listenerList.add(listener);
    }

    public void unRegisterListener(UploadFileListener listener)
    {
        listenerList.remove(listener);
    }

    private void executeNext(Task task)
    {
        executingList.remove(task);
        CWLog.e("file", "executeNext uploadingSize=" + executingList.size()
                + "waitsize=" + taskList.size());
        executeTask();
    }

    /**
     * 取消正在上传的任务
     * 
     * @param path
     *            被取消上传任务的文件路径
     */
    public void cancleUplaod(String path)
    {
        Task task = new Task(new AsyncUploadLargeFile(new String[]{path}, null,
                null, null), 0);
        int index = executingList.indexOf(task);
        if (index != -1)
        {
            Task curTask = executingList.remove(index);
            curTask.uploadTask.cancelUpload();
        }
        else if (taskList.contains(task))
        {
            taskList.remove(task);
        }

    }

    private synchronized void executeTask()
    {
        if (executingList.size() <= MAX_TASK_COUNT)
        {
            final Task task = taskList.poll();
            if (task == null)
            {
                return;
            }
            CWLog.e("file",
                    "executeTask path=" + task.uploadTask.getLocalPath());
            executingList.add(task);
            task.uploadTask
                    .setCallback(new AsyncUploadLargeFile.UploadFileCallback()
                    {
                        @Override
                        public void updateProgress(int transfered, int total)
                        {
                            task.progress = transfered * 100 / total;
                            notifyProgressListener(
                                    task.uploadTask.getLocalPath(), transfered,
                                    total);
                        }

                        @Override
                        public void updateCompleted(Object obj)
                        {
                            notifyCompleteListener(
                                    task.uploadTask.getLocalPath(), obj);
                            executeNext(task);
                        }

                        @Override
                        public void error(int errorCode)
                        {
                            notifyErrorListener(task.uploadTask.getLocalPath(),
                                    errorCode);
                            executeNext(task);
                        }

                        @Override
                        public void uploadCompleted(int resultCode,
                                Object data, String msg)
                        {
                            notifyCompleteObjListener(resultCode, data, msg,
                                    task.uploadTask.getLocalPath());
                            executeNext(task);
                        }
                    });
            task.uploadTask.executeUpload();
        }
    }

    private void notifyProgressListener(String path, int transfered, int total)
    {
        for (UploadFileListener listener : listenerList)
        {
            listener.updateProgress(transfered, total, path);
        }
    }

    private void notifyErrorListener(String path, int errCode)
    {
        for (UploadFileListener listener : listenerList)
        {
            listener.error(errCode, path);
        }
    }

    private void notifyCompleteListener(String path, Object obj)
    {
        for (UploadFileListener listener : listenerList)
        {
            listener.updateCompleted(obj, path);
        }
    }

    private void notifyCompleteObjListener(int resultCode, Object data,
            String msg, String path)
    {
        for (UploadFileListener listener : listenerList)
        {
            listener.uploadCompleted(resultCode, data, msg, path);
        }
    }

    private class TaskComparator implements Comparator<Task>
    {
        @Override
        public int compare(Task lhs, Task rhs)
        {
            return rhs.priori - lhs.priori;
        }
    }

    private class Task
    {
        private AsyncUploadLargeFile uploadTask;

        private int priori;

        private int progress;

        private Task(AsyncUploadLargeFile task, int p)
        {
            this.uploadTask = task;
            this.priori = p;
        }

        @Override
        public boolean equals(Object o)
        {
            String path = ((Task) o).uploadTask.getLocalPath();
            if (this.uploadTask == null || o == null
                    || this.uploadTask.getLocalPath() == null || path == null)
            {
                return false;
            }
            return path.equals(this.uploadTask.getLocalPath());
        }
    }

    public static abstract class UploadFileListener
    {
        /**
         * 更新进度
         *
         * @param transfered
         *            已上传大小
         * @param total
         *            总大小
         */
        public void updateProgress(int transfered, int total, String path)
        {
        }

        /**
         * 上传完成
         */
        public void updateCompleted(Object obj, String path)
        {
        }

        /**
         * 发生异常
         *
         * @param errorCode
         *            异常码
         */
        public void error(int errorCode, String path)
        {
        }

        /**
         * 上传完成
         *
         * @param resultCode
         * @param data
         * @param msg
         */
        public void uploadCompleted(int resultCode, Object data, String msg,
                String path)
        {

        }
    }

    /**
     * 线程优先级
     *
     * @author RES-KUNZHU
     *
     */
    public static class UploadPeriod
    {
        /**
         * 线程优先级 低
         */
        public static final int PERIOD_LOW = 1;

        /**
         * 线程优先级 中
         */
        public static final int PERIOD_MIDDLE = 5;

        /**
         * 线程优先级 高
         */
        public static final int PERIOD_HIGHT = 10;
    }

    public int getProgress(String path)
    {
        int progress = 0;
        if (path != null)
        {
            Task task = new Task(new AsyncUploadLargeFile(new String[]{path},
                    null, null, null), 0);
            int index = executingList.indexOf(task);
            if (index != -1)
            {
                Task tempTask = executingList.get(index);
                progress = tempTask.progress;
            }
        }
        return progress;
    }
}
